<!DOCTYPE html>
<html>
<body>
<canvas id="physicsCanvas" width="800" height="550"></canvas>
<script>
const canvas = document.getElementById('physicsCanvas');
const ctx = canvas.getContext('2d');

// --- Parameters ---
const cx = 400;
const cy = 250; 
const R1 = 90;
const R2 = 130;
const chargeRadius = 5;
const arrowheadSize = 10;
const q_dist = R1 / 2;
const Q_dist = 2 * R2;

// --- Helper Functions ---
function toRad(degrees) { return degrees * Math.PI / 180; }

function drawLine(x1, y1, x2, y2, dashed = false) {
    ctx.beginPath();
    if (dashed) {
        ctx.setLineDash([5, 5]);
    }
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
    if (dashed) {
        ctx.setLineDash([]);
    }
}

function drawArrow(x1, y1, x2, y2) {
    const angle = Math.atan2(y2 - y1, x2 - x1);
    ctx.beginPath();
    ctx.moveTo(x2, y2);
    ctx.lineTo(x2 - arrowheadSize * Math.cos(angle - Math.PI / 6), y2 - arrowheadSize * Math.sin(angle - Math.PI / 6));
    ctx.moveTo(x2, y2);
    ctx.lineTo(x2 - arrowheadSize * Math.cos(angle + Math.PI / 6), y2 - arrowheadSize * Math.sin(angle + Math.PI / 6));
    ctx.stroke();
}

function drawDoubleArrowLine(x1, y1, x2, y2) {
    drawLine(x1, y1, x2, y2);
    drawArrow(x1, y1, x2, y2);
    drawArrow(x2, y2, x1, y1);
}

function drawSubscript(baseText, subText, x, y, font, subFont) {
    ctx.font = font;
    const baseWidth = ctx.measureText(baseText).width;
    ctx.fillText(baseText, x, y);
    ctx.font = subFont;
    ctx.fillText(subText, x + baseWidth / 2, y + 5);
}

function drawFraction(numBase, numSub, den, x, y, font, subFont) {
    const originalFont = ctx.font;
    ctx.textAlign = 'center';
    
    // Numerator
    drawSubscript(numBase, numSub, x, y - 12, font, subFont);

    // Fraction bar
    ctx.beginPath();
    ctx.moveTo(x - 12, y);
    ctx.lineTo(x + 12, y);
    ctx.stroke();
    
    // Denominator
    ctx.font = font;
    ctx.fillText(den, x, y + 12);
    
    ctx.font = originalFont;
}


// --- Main Drawing Logic ---

ctx.strokeStyle = 'black';
ctx.fillStyle = 'black';
ctx.lineWidth = 2;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';

// 1. Draw the conducting shell
ctx.beginPath();
ctx.arc(cx, cy, R1, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(cx, cy, R2, 0, 2 * Math.PI);
ctx.stroke();

// 2. Draw the axes
drawLine(cx - Q_dist - 50, cy, cx + Q_dist + 50, cy, true);
const axisAngle = toRad(-45);
const axisLength = R1 * 1.2;
drawLine(cx - axisLength * Math.cos(axisAngle), cy - axisLength * Math.sin(axisAngle),
         cx + axisLength * Math.cos(axisAngle), cy + axisLength * Math.sin(axisAngle), true);

// 3. Draw Center Mark
ctx.save();
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.moveTo(cx - 4, cy - 4);
ctx.lineTo(cx + 4, cy + 4);
ctx.moveTo(cx + 4, cy - 4);
ctx.lineTo(cx - 4, cy + 4);
ctx.stroke();
ctx.restore();

// 4. Draw Diameter Lines and Labels (as per the image's notation)
const baseFont = 'italic 20px Times New Roman';
const subFont = 'italic 14px Times New Roman';

// R2 diameter line
const R2_diam_angle = toRad(135);
const R2_x1 = cx + R2 * Math.cos(R2_diam_angle);
const R2_y1 = cy + R2 * Math.sin(R2_diam_angle);
const R2_x2 = cx - R2 * Math.cos(R2_diam_angle);
const R2_y2 = cy - R2 * Math.sin(R2_diam_angle);
drawDoubleArrowLine(R2_x1, R2_y1, R2_x2, R2_y2);
drawSubscript('R', '2', R2_x1 - 25, R2_y1 - 15, baseFont, subFont);

// R1 diameter line
const R1_diam_angle = toRad(45);
const R1_x1 = cx + R1 * Math.cos(R1_diam_angle);
const R1_y1 = cy + R1 * Math.sin(R1_diam_angle);
const R1_x2 = cx - R1 * Math.cos(R1_diam_angle);
const R1_y2 = cy - R1 * Math.sin(R1_diam_angle);
drawDoubleArrowLine(R1_x1, R1_y1, R1_x2, R1_y2);
drawSubscript('R', '1', R1_x2 + 25, R1_y2 + 15, baseFont, subFont);


// 5. Draw Charges and Labels
ctx.font = 'italic 22px Times New Roman';
// Outer charges Q
const Q_left_x = cx - Q_dist;
ctx.beginPath(); ctx.arc(Q_left_x, cy, chargeRadius, 0, 2 * Math.PI); ctx.fill();
ctx.fillText('Q', Q_left_x, cy - 25);

const Q_right_x = cx + Q_dist;
ctx.beginPath(); ctx.arc(Q_right_x, cy, chargeRadius, 0, 2 * Math.PI); ctx.fill();
ctx.fillText('Q', Q_right_x, cy - 25);

// Inner charges q
const q_angle_rad = toRad(-45);
const q_ur_x = cx + q_dist * Math.cos(q_angle_rad);
const q_ur_y = cy + q_dist * Math.sin(q_angle_rad);
ctx.beginPath(); ctx.arc(q_ur_x, q_ur_y, chargeRadius, 0, 2 * Math.PI); ctx.fill();
ctx.fillText('q', q_ur_x + 18, q_ur_y - 18);

const q_ll_x = cx - q_dist * Math.cos(q_angle_rad);
const q_ll_y = cy - q_dist * Math.sin(q_angle_rad);
ctx.beginPath(); ctx.arc(q_ll_x, q_ll_y, chargeRadius, 0, 2 * Math.PI); ctx.fill();
ctx.fillText('q', q_ll_x - 18, q_ll_y + 18);


// 6. Draw Distance and Angle Labels
// Distance 2R2
ctx.fillStyle = 'white'; // Create a gap in the dashed line for the label
ctx.fillRect(cx - (Q_dist + R2)/2 - 25, cy - 12, 50, 24);
ctx.fillRect(cx + (Q_dist + R2)/2 - 25, cy - 12, 50, 24);
ctx.fillStyle = 'black';
drawSubscript('2R', '2', cx - (Q_dist + R2)/2, cy, baseFont, subFont);
drawSubscript('2R', '2', cx + (Q_dist + R2)/2, cy, baseFont, subFont);


// Distance R1/2
drawLine(cx, cy, q_ur_x, q_ur_y);
drawFraction('R', '1', '2', q_ur_x - 25, q_ur_y - 25, baseFont, subFont);

drawLine(cx, cy, q_ll_x, q_ll_y);
drawFraction('R', '1', '2', q_ll_x + 25, q_ll_y + 25, baseFont, subFont);


// Angle 45°
ctx.beginPath();
ctx.arc(cx, cy, 30, 0, q_angle_rad, true); // Clockwise arc
ctx.stroke();
ctx.font = '18px Times New Roman';
ctx.fillText('45°', cx + 45 * Math.cos(toRad(-22.5)), cy + 45 * Math.sin(toRad(-22.5)));

// 7. Draw the main text label
ctx.font = '24px KaiTi';
ctx.fillText('导体球壳', cx, cy + R2 + 60);

</script>
</body>
</html>